{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "nbsphinx": "hidden"
   },
   "source": [
    "This notebook is part of the `kikuchipy` documentation https://kikuchipy.org.\n",
    "Links to the documentation won't work from the notebook."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Virtual backscatter electron imaging"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Interactive plotting\n",
    "\n",
    "Angle resolved backscatter electron (BSE) imaging can be performed interactively\n",
    "with the method\n",
    "[plot_virtual_bse_intensity()](reference.rst#kikuchipy.signals.EBSD.plot_virtual_bse_intensity),\n",
    "adopted from [pyxem](https://github.com/pyxem/pyxem), by integrating the\n",
    "intensities within a part, e.g. a (10 x 10) pixel rectangular region of interest\n",
    "(ROI), of the stack of EBSD patterns. Let's first import necessary libraries\n",
    "and a 13 MB Nickel EBSD data set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exchange inline for notebook or qt5 (from pyqt) for interactive plotting\n",
    "%matplotlib inline\n",
    "\n",
    "import tempfile\n",
    "import hyperspy.api as hs\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import kikuchipy as kp\n",
    "\n",
    "\n",
    "plt.rcParams[\"font.size\"] = 12\n",
    "\n",
    "\n",
    "s = kp.data.nickel_ebsd_large(allow_download=True)  # External download\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create a rectangular ROI by specifying the upper left and lower right\n",
    "coordinates of the rectangle in units of the detector pixel size (scale of `dx`\n",
    "and `dy` in the signal axes manager)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "roi = hs.roi.RectangularROI(left=0, top=0, right=10, bottom=10)\n",
    "s.plot_virtual_bse_intensity(roi)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below is an animation showing the output three output windows of the above\n",
    "method: navigator to the left (the navigator image created from *all*\n",
    "intensities on the detector, not just within an ROI), detector in the middle\n",
    "with the adjustable ROI, and the virtual BSE image generated from the\n",
    "intensities within the ROI to the right."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"_static/image/virtual_backscatter_electron_imaging/virtual_backscatter_electron_imaging.gif\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the position of the ROI on the detector is updated during the\n",
    "interactive plotting. See\n",
    "[HyperSpy's ROI user guide](http://hyperspy.org/hyperspy-doc/current/user_guide/interactive_operations_ROIs.html#region-of-interest-roi)\n",
    "for more detailed use of ROIs.\n",
    "\n",
    "The virtual image, created from integrating the intensities within the ROI, can\n",
    "then be written to an image file using\n",
    "[get_virtual_bse_intensity()](reference.rst#kikuchipy.signals.EBSD.get_virtual_bse_intensity)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse = s.get_virtual_bse_intensity(roi)\n",
    "vbse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_dir = tempfile.mkdtemp() + \"/\"\n",
    "plt.imsave(temp_dir + \"vbse1.png\", arr=vbse.data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A [VirtualBSEImage](reference.rst#kikuchipy.signals.VirtualBSEImage) instance is\n",
    "returned."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generate many virtual images\n",
    "\n",
    "Sometimes we want to get many images from parts of the detector, e.g. like what\n",
    "is demonstrated in the\n",
    "[xcdskd project](https://xcdskd.readthedocs.io/en/latest/bse_imaging.html) with\n",
    "the angle resolved virtual backscatter electron array (arbse/vbse array).\n",
    "Instead of keeping track of multiple\n",
    "[hyperspy.roi.BaseInteractiveROI](http://hyperspy.org/hyperspy-doc/current/api/hyperspy.roi.html#hyperspy.roi.BaseInteractiveROI)\n",
    "objects, we can create a detector grid of a certain shape, e.g. (5, 5), and\n",
    "obtain gray scale images, or combine multiple grid tiles in red, green and\n",
    "channels to obtain RGB images.\n",
    "\n",
    "First, we initialize a virtual BSE image generator,\n",
    "[kikuchipy.generators.VirtualBSEGenerator](reference.rst#kikuchipy.generators.VirtualBSEGenerator),\n",
    "with an [EBSD](reference.rst#kikuchipy.signals.EBSD) signal, in this case the\n",
    "raw EBSD patterns without any background correction or other processing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_gen = kp.generators.VirtualBSEGenerator(s)\n",
    "vbse_gen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can set and plot the detector grid on one of the EBSD patterns, also coloring\n",
    "one or more of the grid tiles red, green and blue, as is done in\n",
    "<cite data-cite=\"nolze2017electron\">Nolze et al. (2017)</cite>, by calling\n",
    "[VirtualBSEGenerator.plot_grid()](reference.rst#kikuchipy.generators.VirtualBSEGenerator.plot_grid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_gen.grid_shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_gen.grid_shape = (10, 10)\n",
    "red = [(7, 1), (8, 1), (8, 2), (9, 1), (9, 2)]\n",
    "green = [(8, 4), (8, 5), (9, 4), (9, 5)]\n",
    "blue = [(7, 8), (8, 7), (8, 8), (9, 7), (9, 8)]\n",
    "p = vbse_gen.plot_grid(\n",
    "    rgb_channels=[red, green, blue],\n",
    "    visible_indices=True,  # Default\n",
    "    pattern_idx=(10, 20),  # Default is (0, 0)\n",
    ")\n",
    "p"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As shown above, whether to show the grid tile indices or not is controlled with\n",
    "the `visible_indices` argument, and which signal pattern to superimpose the grid\n",
    "upon is controlled with the `pattern_idx` parameter."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To obtain an RGB image from the detector grid tiles shown above, we use\n",
    "[get_rgb_image()](reference.rst#kikuchipy.generators.VirtualBSEGenerator.get_rgb_image)\n",
    "(see the docstring for all available parameters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_rgb_img = vbse_gen.get_rgb_image(r=red, g=green, b=blue)\n",
    "vbse_rgb_img"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx-thumbnail": {
     "tooltip": "Interactive angle resolved backscatter electron imaging by integrating intensities within regions of interest on the detector"
    },
    "tags": [
     "nbsphinx-thumbnail"
    ]
   },
   "outputs": [],
   "source": [
    "vbse_rgb_img.plot(title=\"\", axes_off=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An RGB image formed from coloring three grey scale virtual BSE images red,\n",
    "green and blue."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To obtain one grey scale virtual BSE image from each grid tile, we use\n",
    "[get_images_from_grid()](reference.rst#kikuchipy.generators.VirtualBSEGenerator.get_images_from_grid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_gen.grid_shape = (3, 3)\n",
    "vbse_imgs = vbse_gen.get_images_from_grid()\n",
    "vbse_imgs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_imgs.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(20, 20))\n",
    "for idx in np.ndindex(vbse_imgs.axes_manager.navigation_shape[::-1]):\n",
    "    hs_idx = idx[::-1]  # HyperSpy uses (col, row) instead of NumPy's (row, col)\n",
    "    ax[idx].imshow(vbse_imgs.inav[hs_idx].data, cmap=\"gray\")\n",
    "    ax[idx].axis(\"off\")\n",
    "fig.tight_layout(w_pad=0.5, h_pad=-24)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It might be desirable to normalize, rescale or stretch the intensities in the\n",
    "images, as shown e.g. in Fig. 9 in\n",
    "<cite data-cite=\"wright2015electron\">Wright et al. (2015)</cite>. This can be\n",
    "done with\n",
    "[VirtualBSEImage.normalize_intensity()](reference.rst#kikuchipy.signals.VirtualBSEImage.normalize_intensity)\n",
    "or\n",
    "[VirtualBSEImage.rescale_intensity()](reference.rst#kikuchipy.signals.VirtualBSEImage.rescale_intensity).\n",
    "Let's rescale the intensities in each image to the range [0, 1], while also\n",
    "excluding the intensities outside the lower and upper 0.5% percentile, per image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_imgs.data.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vbse_imgs2 = vbse_imgs.deepcopy()\n",
    "vbse_imgs2.rescale_intensity(out_range=(0, 1), percentiles=(0.5, 99.5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(vbse_imgs.data.min(), vbse_imgs.data.max())\n",
    "print(vbse_imgs2.data.min(), vbse_imgs2.data.max())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(20, 20))\n",
    "for idx in np.ndindex(vbse_imgs2.axes_manager.navigation_shape[::-1]):\n",
    "    hs_idx = idx[::-1]\n",
    "    ax[idx].imshow(vbse_imgs2.inav[hs_idx].data, cmap=\"gray\")\n",
    "    ax[idx].axis(\"off\")\n",
    "fig.tight_layout(w_pad=0.5, h_pad=-24)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To obtain a rectangular ROI from the grid, we can use\n",
    "[VirtualBSEGenerator.roi_from_grid()](reference.rst#kikuchipy.generators.VirtualBSEGenerator.roi_from_grid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "roi2 = vbse_gen.roi_from_grid((3, 3))  # (Row, column)\n",
    "roi2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "nbsphinx": "hidden"
   },
   "outputs": [],
   "source": [
    "# Remove files written to disk in this user guide\n",
    "import os\n",
    "os.remove(temp_dir + \"vbse1.png\")\n",
    "os.rmdir(temp_dir)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
